package com.randi.system.service.impl;

import com.github.pagehelper.PageInfo;
import com.randi.common.config.AppConfig;
import com.randi.common.constant.CacheConstants;
import com.randi.common.core.domain.entity.SysUser;
import com.randi.common.utils.page.PageHelperUtils;
import com.randi.system.domain.params.SysUserParam;
import com.randi.common.enums.ResultCode;
import com.randi.common.exception.ServiceException;
import com.randi.common.utils.ArrayUtils;
import com.randi.system.domain.entity.SysUserRole;
import com.randi.system.domain.dto.UserRoleDTO;
import com.randi.system.mapper.SysUserRoleMapper;
import com.randi.system.service.ISysUserRoleService;
import com.randi.system.service.ISysUserService;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author ziye
 */
@Service
@CacheConfig(cacheNames = CacheConstants.SYS_USER_ROLE)
public class SysUserRoleServiceImpl implements ISysUserRoleService {

    @Resource
    private ISysUserService iSysUserService;

    @Resource
    private SysUserRoleMapper sysUserRoleMapper;

    @Resource
    private AppConfig.SystemConfig systemConfig;

    /**
     * 分页获取授权用户列表
     *
     * @param roleId    角色ID
     * @param allocated 是否授权
     * @param userParam 检索参数
     * @return 用户列表
     */
    @Override
    @Cacheable(keyGenerator = "baseKeyGenerator", unless = "#result == null")
    public PageInfo<SysUser> selectAllocatedUserList(Long roleId, Boolean allocated, SysUserParam userParam) {
        Optional.ofNullable(userParam).orElseThrow(() -> new ServiceException(ResultCode.PARAM_ERROR));

        if (roleId.equals(systemConfig.getRoleAdminId())) {
            return new PageInfo<>(Collections.emptyList());
        }

        // 获取已分配角色的用户列表
        List<Long> userIdList = this.selectSysUserRoleUserIdList(roleId);
        if (allocated && userIdList.isEmpty()) {
            return new PageInfo<>(Collections.emptyList());
        }

        if (allocated) {
            userParam.setIncludes(userIdList);
        } else {
            userIdList.add(systemConfig.getUserAdminId());
            userParam.setExcludes(userIdList);
        }
        return iSysUserService.selectPageList(userParam);
    }

    /**
     * 授权查询
     *
     * @param roleId 角色ID
     * @return 结果
     */
    @Override
    @Cacheable(key = "#roleId", unless = "#result == null or #result.isEmpty()")
    public List<Long> selectSysUserRoleUserIdList(Long roleId) {
        return sysUserRoleMapper.selectSysUserRoleByRoleId(roleId);
    }

    /**
     * 添加用户授权
     *
     * @param userRoleDto UserRoleBody
     * @return 结果
     */
    @Override
    @CacheEvict(allEntries = true, beforeInvocation = true)
    @Transactional(rollbackFor = Exception.class)
    public int addAuthUsers(UserRoleDTO userRoleDto) {
        Long roleId = userRoleDto.getRoleId();

        if (roleId.equals(systemConfig.getRoleAdminId())) {
            throw new ServiceException(ResultCode.BUSINESS_ROLE_AUTH_ERROR_ADMIN);
        }

        List<Long> original = sysUserRoleMapper.selectSysUserRoleByRoleId(roleId);
        // 管理员ID
        original.add(systemConfig.getUserAdminId());

        List<Long> current = userRoleDto.getUserIds();

        List<SysUserRole> sysUserRoleList = ArrayUtils.difference(current, original).stream()
                .map(userId -> new SysUserRole(roleId, userId))
                .collect(Collectors.toList());

        if (sysUserRoleList.isEmpty()) {
            throw new ServiceException(ResultCode.BUSINESS_ROLE_AUTH_ERROR_NO_USER);
        }

        return sysUserRoleMapper.insertBatch(sysUserRoleList);
    }

    /**
     * 取消用户授权
     *
     * @param userRoleDto UserRoleBody
     * @return 结果
     */
    @Override
    @CacheEvict(allEntries = true, beforeInvocation = true)
    @Transactional(rollbackFor = Exception.class)
    public int cancelAuthUsers(UserRoleDTO userRoleDto) {
        Long roleId = userRoleDto.getRoleId();

        if (roleId.equals(systemConfig.getRoleAdminId())) {
            throw new ServiceException(ResultCode.BUSINESS_ROLE_AUTH_ERROR_ADMIN);
        }

        List<Long> userIds = sysUserRoleMapper.selectSysUserRoleByRoleId(roleId);

        List<Long> userIdList = userRoleDto.getUserIds().stream()
                .filter(userIds::contains)
                .collect(Collectors.toList());

        if (userIdList.isEmpty()) {
            throw new ServiceException(ResultCode.BUSINESS_ROLE_AUTH_ERROR_NO_USER);
        }

        return sysUserRoleMapper.deleteBatch(roleId, userIdList);
    }

}
